html-react-parser
HTML to React parser that works on both the server (Node.js) and the client (browser):
HTMLReactParser(string[, options])
It converts an HTML string to one or more React elements. There's also an option to replace an element with your own.
Example:
const parse = require('html-react-parser');
parse('<div>text</div>');
CodeSandbox | Repl.it | JSFiddle | Examples
Table of Contents
Install
NPM:
$ npm install html-react-parser --save
Yarn:
$ yarn add html-react-parser
CDN:
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/html-react-parser@latest/dist/html-react-parser.min.js"></script>
<script>
window.HTMLReactParser();
</script>
Usage
Import or require the module:
import parse from 'html-react-parser';
const parse = require('html-react-parser');
Parse single element:
parse('<h1>single</h1>');
Parse multiple elements:
parse('<li>Item 1</li><li>Item 2</li>');
Since adjacent elements are parsed as an array, make sure to render them under a parent node:
<ul>
{parse(`
<li>Item 1</li>
<li>Item 2</li>
`)}
</ul>
Parse nested elements:
parse('<body><p>Lorem ipsum</p></body>');
Parse element with attributes:
parse(
'<hr id="foo" class="bar" data-attr="baz" custom="qux" style="top:42px;">'
);
Options
replace(domNode)
The replace
callback allows you to swap an element with another React element.
The first argument is an object with the same output as htmlparser2's domhandler:
parse('<br>', {
replace: function (domNode) {
console.dir(domNode, { depth: null });
}
});
Console output:
{ type: 'tag',
name: 'br',
attribs: {},
children: [],
next: null,
prev: null,
parent: null }
The element is replaced only if a valid React element is returned:
parse('<p id="replace">text</p>', {
replace: domNode => {
if (domNode.attribs && domNode.attribs.id === 'replace') {
return React.createElement('span', {}, 'replaced');
}
}
});
Here's an example that modifies an element but keeps the children:
import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import parse, { domToReact } from 'html-react-parser';
const html = `
<p id="main">
<span class="prettify">
keep me and make me pretty!
</span>
</p>
`;
const options = {
replace: ({ attribs, children }) => {
if (!attribs) return;
if (attribs.id === 'main') {
return <h1 style={{ fontSize: 42 }}>{domToReact(children, options)}</h1>;
}
if (attribs.class === 'prettify') {
return (
<span style={{ color: 'hotpink' }}>
{domToReact(children, options)}
</span>
);
}
}
};
console.log(renderToStaticMarkup(parse(html, options)));
Use the exported attributesToProps method to convert DOM attributes to React Props:
import React from 'react';
import parse, { attributesToProps } from 'html-react-parser';
const html = `
<hr class="prettify" style="background:#fff;text-align:center" />
`;
const options = {
replace: node => {
if (node.attribs && node.name === 'hr') {
const props = attributesToProps(node.attribs);
return <hr {...props} />;
}
}
};
Output:
<h1 style="font-size:42px">
<span style="color:hotpink"> keep me and make me pretty! </span>
</h1>
Here's an example that excludes an element:
parse('<p><br id="remove"></p>', {
replace: ({ attribs }) => attribs && attribs.id === 'remove' && <Fragment />
});
library
The library
option allows you to specify which component library is used to create elements. React is used by default if this option is not specified.
Here's an example showing how to use Preact:
parse('<br>', {
library: require('preact')
});
Or, using a custom library:
parse('<br>', {
library: {
cloneElement: () => {
},
createElement: () => {
},
isValidElement: () => {
}
}
});
htmlparser2
The default options passed to htmlparser2 are:
{
decodeEntities: true,
lowerCaseAttributeNames: false
}
Since v0.12.0, you can override the default options by passing htmlparser2 options.
Here's an example in which decodeEntities
and xmlMode
are enabled:
parse('<p /><p />', {
htmlparser2: {
decodeEntities: true,
xmlMode: true
}
});
Warning: htmlparser2
is only applicable on the server-side (Node.js) and not applicable on the client-side (browser). By overriding htmlparser2
options, there's a chance that universal rendering breaks. Do this at your own risk.
trim
Normally, whitespace is preserved:
parse('<br>\n');
By enabling the trim
option, whitespace text nodes will be skipped:
parse('<br>\n', { trim: true });
This addresses the warning:
Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of <table>. Make sure you don't have any extra whitespace between tags on each line of your source code.
However, this option may strip out intentional whitespace:
parse('<p> </p>', { trim: true });
FAQ
Is this XSS safe?
No, this library is not XSS (cross-site scripting) safe. See #94.
Does invalid HTML get sanitized?
No, this library does not sanitize HTML. See #124, #125, and #141.
Are <script>
tags parsed?
Although <script>
tags and their contents are rendered on the server-side, they're not evaluated on the client-side. See #98.
Attributes aren't getting called
The reason why your HTML attributes aren't getting called is because inline event handlers (e.g., onclick
) are parsed as a string rather than a function. See #73.
Parser throws an error
If the parser throws an erorr, check if your arguments are valid. See "Does invalid HTML get sanitized?".
Is SSR supported?
Yes, server-side rendering on Node.js is supported by this library. See demo.
Elements aren't nested correctly
If your elements are nested incorrectly, check to make sure your HTML markup is valid. The HTML to DOM parsing will be affected if you're using self-closing syntax (/>
) on non-void elements:
parse('<div /><div />');
See #158.
Warning: validateDOMNesting(...): Whitespace text nodes cannot appear as a child of table
Enable the trim option. See #155.
Don't change case of tags
Tags are lowercased by default. To prevent that from happening, pass the htmlparser2 option:
const options = {
htmlparser2: {
lowerCaseTags: false
}
};
parse('<CustomElement>', options);
Warning: By preserving case-sensitivity of the tags, you may get rendering warnings like:
Warning: <CustomElement> is using incorrect casing. Use PascalCase for React components, or lowercase for HTML elements.
See #62 and example.
Benchmarks
$ npm run test:benchmark
Here's an example output of the benchmarks run on a MacBook Pro 2017:
html-to-react - Single x 415,186 ops/sec ±0.92% (85 runs sampled)
html-to-react - Multiple x 139,780 ops/sec ±2.32% (87 runs sampled)
html-to-react - Complex x 8,118 ops/sec ±2.99% (82 runs sampled)
Contributors
Code Contributors
This project exists thanks to all the people who contribute. [Contribute].
Financial Contributors
Become a financial contributor and help us sustain our community. [Contribute]
Individuals
Organizations
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]
Support
License
MIT